#include "i2c_device_tree.h" // I2C device tree functions and definitions

//  8-bit binary-coded decimal
typedef uint8_t bcd8_t;

// byte
typedef uint8_t byte_t;

// bit
typedef bool bit_t;

// m41t6x read write function handle
typedef esp_err_t (*m41t6x_transmit_handle)(uint8_t address, uint8_t *data_out, uint8_t len);

// alarm repeat mode
typedef enum
{
    M41T6X_RPT_SEC = 0x1F,
    M41T6X_RPT_MIN = 0x0F,
    M41T6X_RPT_HOUR = 0x07,
    M41T6X_RPT_DAY = 0x03,
    M41T6X_RPT_MON = 0x01,
    M41T6X_RPT_YEAR = 0x00
} m41t6x_rpt_t;

// watchdog resolution
typedef enum _watchdog_resolution_t_
{
    M41T6X_WATCHDOG_16_HZ = 0x00,
    M41T6X_WATCHDOG_4_HZ = 0x01,
    M41T6X_WATCHDOG_1_HZ = 0x02,
    M41T6X_WATCHDOG_1_4_HZ = 0x03,
    M41T6X_WATCHDOG_1_60_HZ = 0x80
} wtd_res_t;

// square wave frequency
typedef enum
{
    M41T6X_SQW_NONE = 0x00,     // Close square wave output
    M41T6X_SQW_32768_HZ = 0x10, // square wave output 32768 Hz
    M41T6X_SQW_8192_HZ = 0x20,  // square wave output 8192 Hz
    M41T6X_SQW_4096_HZ = 0x30,  // square wave output 4096 Hz
    M41T6X_SQW_2048_HZ = 0x40,  // square wave output 2048 Hz
    M41T6X_SQW_1024_HZ = 0x50,  // square wave output 1024 Hz
    M41T6X_SQW_512_HZ = 0x60,   // square wave output 512 Hz
    M41T6X_SQW_256_HZ = 0x70,   // square wave output 256 Hz
    M41T6X_SQW_128_HZ = 0x80,   // square wave output 128 Hz
    M41T6X_SQW_64_HZ = 0x90,    // square wave output 64 Hz
    M41T6X_SQW_32_HZ = 0xA0,    // square wave output 32 Hz
    M41T6X_SQW_16_HZ = 0xB0,    // square wave output 16 Hz
    M41T6X_SQW_8_HZ = 0xC0,     // square wave output 8 Hz
    M41T6X_SQW_4_HZ = 0xD0,     // square wave output 4 Hz
    M41T6X_SQW_2_HZ = 0xE0,     // square wave output 2 Hz
    M41T6X_SQW_1_HZ = 0xF0,     // square wave output 1
} m41t6x_sqw_t;

// real time clock structure
typedef struct
{
    uint8_t centisecond; // uint is 0.01s, code is uint8_t
    uint8_t second;      // uint is 0.1s, code is uint8_t
    uint8_t minute;      // uint is 1s, code is uint8_t
    uint8_t hour;        // uint is 1h, code is uint8_t
    uint8_t day;         // uint is 1d, code is uint8_t
    uint8_t date;        // uint is 1d, code is uint8_t
    uint8_t month;       // uint is 1m, code is uint8_t
    uint16_t year;       // uint is 1y, code is uint16_t
} rtc_time_t;

// real time clock chip structure
typedef struct _m41t6x_t
{

    // time
    rtc_time_t time; // time, from m41t6x chip

    // get m41t6x time
    esp_err_t (*time_get)(rtc_time_t *time);

    // set m41t6x time
    esp_err_t (*time_set)(rtc_time_t *time);

    // sync time
    esp_err_t (*sync_time)(void);

    // m41t6x alarm control functions
    struct
    {
        // enable alarm interrupt flag
        esp_err_t (*enable_af)(void);

        // disable alarm interrupt flag
        esp_err_t (*disable_af)(void);

        // get alarm interrupt flag
        esp_err_t (*afe_get)(bit_t *afe);

        // get alarm flag
        esp_err_t (*flag_get)(bit_t *af);

        // get alarm time
        esp_err_t (*get)(rtc_time_t *alarm);

        // set alarm time
        esp_err_t (*set)(rtc_time_t alarm);

        // delete alarm
        esp_err_t (*delete)(void);

        // get alarm repeat mode
        esp_err_t (*repeat_mode_get)(m41t6x_rpt_t *rpt);

        // set alarm repeat mode
        esp_err_t (*repeat_mode_set)(m41t6x_rpt_t rpt);
    } alarm;

    // m41t6x square wave control functions
    struct
    {
        // get square wave wave status
        esp_err_t (*status_get)(bit_t *sqwe);

        // enable square wave output
        esp_err_t (*open)(void);

        // disable square wave output
        esp_err_t (*close)(void);

        // get square wave output frequency
        esp_err_t (*get)(m41t6x_sqw_t *sqw);

        // set square wave output frequency
        esp_err_t (*set)(m41t6x_sqw_t sqw);
    } sqw;

    // m41t6x oscillator control functions
    struct
    {
        // get oscillator fail interrupt status
        esp_err_t (*intr_get)(bit_t *status);

        // oscillator fail interrupt enable
        esp_err_t (*intr_enable)();

        // oscillator fail interrupt disable
        esp_err_t (*intr_disable)();

        // get oscillator failed
        esp_err_t (*failed_get)(bit_t *of);

        // set oscillator failed
        esp_err_t (*failed_set)(bit_t of);

        // run oscillator
        esp_err_t (*run)(void);

        // stop oscillator
        esp_err_t (*stop)(void);

        // get oscillator status
        esp_err_t (*status_get)(bit_t *status);
    } osc;

    // m41t6x watchdog control functions
    struct
    {
        // set watchdog multiplier bits and watchdog resulotion bits
        esp_err_t (*set)(uint8_t wtd_mul, wtd_res_t wtd);

        // get watchdog multiplier bits and watchdog resulotion bits
        esp_err_t (*get)(uint8_t *wtd_mul, wtd_res_t *wtd);

        // get watchdog status
        esp_err_t (*status_get)(bit_t *wdf);
    } wtd;

    // m41t6x calibration control functions
    struct
    {
        // set calibration value
        esp_err_t (*set)(uint8_t calibration);

        // get calibration value
        esp_err_t (*get)(uint8_t *calibration);
    } cal;

    // m41t6x output level control functions
    struct
    {
        // set output level
        esp_err_t (*level_set)(bit_t out);

        // get output level
        esp_err_t (*level_get)(bit_t *out);
    } out;

    // i2c bus transmission functions
    struct
    {
        // esp_err_t (*write)(uint8_t reg_adr, uint8_t *data, uint8_t size);
        // esp_err_t (*read)(uint8_t reg_adr, uint8_t *data, uint8_t size);
        m41t6x_transmit_handle write;
        m41t6x_transmit_handle read;

        // i2c device
        i2c_dev_lst_t *dev;
    } i2c;

} m41t6x_t;

typedef m41t6x_t *m41t6x_handle;

esp_err_t m41t6x_init(m41t6x_handle *dhandle,
                      i2c_dev_lst_t *i2c_dev_lst,
                      m41t6x_transmit_handle write,
                      m41t6x_transmit_handle read);
esp_err_t m41t6x_deinit(m41t6x_handle *dhandle);
